#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <sstream>
#include <fstream>
#include <functional>

const static std::string base_sep = "\r\n";
const static std::string line_sep = ": ";
const static std::string space_sep = " ";
const static std::string prefixpath = "wwwroot";
const static std::string homepage = "index.html";
const static std::string httpversion = "HTTP/1.0";
const static std::string suffix_sep = ".";
const static std::string arg_sep = "?";

class HttpRequest
{
private:
    // 取下 请求串 的一行
    std::string Getline(std::string &reqstr)
    {
        // 以行为单位，初步反序列化
        size_t pos = reqstr.find(base_sep);
        if (pos == std::string::npos)
            return std::string(); // 找不到换行，说明不完整

        // 找到换行符，取下一行
        std::string line = reqstr.substr(0, pos);
        reqstr.erase(0, line.size() + base_sep.size()); // 删除读取过的行

        // 返回时检查，读取到空行就返回 \r\n
        return line.empty() ? base_sep : line;
    }

    // 拆分请求行
    void ParseReqline()
    {
        // 见字符串转换为流
        std::stringstream ss(_req_line);
        // 可以使字符串像流一样使用
        ss >> _method >> _url >> _version;

        // 请求方法为 GET  /login?username=xxxx
        if (strcasecmp(_method.c_str(), "GET") == 0)
        {
            // 取下参数，放到正文
            size_t pos = _url.find(arg_sep);
            if (pos != std::string::npos)
            {
                _req_bodytext = _url.substr(pos + arg_sep.size());
                // 删除url中的参数
                _url.resize(pos);
            }
        }

        _path += _url;
        // 资源路径
        if (_url == "/")
            _path += homepage;

        // 文件后缀
        size_t pos = _path.rfind(suffix_sep);
        if (pos == std::string::npos)
        {
            _suffix = ".default";
        }
        else
        {
            _suffix = _path.substr(pos);
        }
    }

    // 拆分请求报头
    void ParseHeaders()
    {
        for (auto &header : _req_headers)
        {
            // key: val
            size_t pos = header.find(line_sep);
            if (pos == std::string::npos)
                continue;

            std::string key = header.substr(0, pos);
            std::string val = header.substr(pos + line_sep.size());

            _headers_kv[key] = val;
        }
    }

public:
    HttpRequest() : _blank_line("\r\n"), _path(prefixpath)
    {
    }
    ~HttpRequest()
    {
    }

    void Deserialize(std::string &reqstr)
    {
        // 基本反序列化
        _req_line = Getline(reqstr); // 请求行
        // 请求报头
        std::string head;
        while (1)
        {
            head = Getline(reqstr);
            if (head.empty())
                break; // 说明没有换行符
            if (head == base_sep)
                break; // 空行，下面该正文了

            _req_headers.push_back(head);
        }
        // 请求正文
        if (!reqstr.empty())
            _req_bodytext = reqstr;

        // 进一步反序列化
        ParseReqline();
        ParseHeaders();
    }

    void Print()
    {
        std::cout << "-----------------------------" << std::endl;
        // 请求行
        std::cout << "@@@ " << _req_line << std::endl;
        // 请求报头
        for (auto &header : _req_headers)
        {
            std::cout << "### " << header << std::endl;
        }
        // 空行
        std::cout << "$$$ " << _blank_line;
        // 请求正文
        std::cout << "%%% " << _req_bodytext << std::endl;

        // 进一步反序列化
        std::cout << "Method: " << _method << std::endl;
        std::cout << "URL: " << _url << std::endl;
        std::cout << "Version: " << _version << std::endl;
        for (auto &[key, val] : _headers_kv)
        {
            std::cout << "^^^ " << key << "->" << val << std::endl;
        }
    }

    std::string Url()
    {
        LOG(DEBUG, "Client want url: %s\n", _url.c_str());
        return _url;
    }

    std::string Path()
    {
        LOG(DEBUG, "Client want path: %s\n", _path.c_str());
        return _path;
    }

    std::string Suffix()
    {
        return _suffix;
    }

    std::string GetRequestBody()
    {
        LOG(DEBUG, "client request method: %s, args: %s, path: %s\n", 
        _method.c_str(), _req_bodytext.c_str(), _path.c_str());
        return _req_bodytext;
    }
private:
    // 基本的 request 格式
    std::string _req_line;                 // 请求行
    std::vector<std::string> _req_headers; // 请求报头
    std::string _blank_line;               // 空行
    std::string _req_bodytext;             // 请求正文

    // 进一步序列化
    // 请求行拆分
    std::string _method;
    std::string _url;
    std::string _path;
    std::string _suffix;
    std::string _version;
    // 请求报头
    std::unordered_map<std::string, std::string> _headers_kv;
};

class HttpResponse
{
public:
    HttpResponse() : _version(httpversion), _blank_line(base_sep)
    {
    }
    ~HttpResponse()
    {
    }

    // 添加状态码
    void AddCode(int code, const std::string &desc)
    {
        _code = code;
        _desc = desc;
    }

    // 添加报头属性
    void AddHeader(const std::string &key, const std::string &val)
    {
        _headers_kv[key] = val;
    }

    // 添加正文
    void AddBodyText(const std::string &body_text)
    {
        _resp_bodytext = body_text;
    }

    // 序列化
    std::string Serialize()
    {
        // 1.构建状态行
        _status_line = _version + space_sep + std::to_string(_code) + space_sep + _desc + base_sep;

        // 2.构建响应报头
        for (auto &[k, v] : _headers_kv)
        {
            _headers.push_back(k + line_sep + v + base_sep);
        }

        // 3.空行，响应正文，已经有了

        // 4.序列化
        std::string respstr = _status_line;
        for (auto &header : _headers)
        {
            respstr += header;
        }
        respstr += _blank_line;
        respstr += _resp_bodytext;

        return respstr;
    }

private:
    // 基本属性
    std::string _version;                                     // http 版本
    int _code;                                                // 状态码
    std::string _desc;                                        // 状态描述
    std::unordered_map<std::string, std::string> _headers_kv; // 请求报头

    // 以行为单位的，Response 基本格式
    std::string _status_line;          // 状态行
    std::vector<std::string> _headers; // 请求报头
    std::string _blank_line;           // 空行
    std::string _resp_bodytext;        // 响应正文
};


using func_t = std::function<HttpResponse(HttpRequest&)>;
class HttpServer
{
private:
    std::string GetFileContent(const std::string &path)
    {
        // 打开资源文件
        std::ifstream in(path, std::ios::binary); // 以二进制方式打开文件
        if (!in.is_open())
            return std::string();

        // 获取文件大小
        in.seekg(0, in.end);       // 文件中存在一个类似指针的东西，将其移动到文件末尾
        int filesize = in.tellg(); // 获取指针偏移量，相当于计算文件大小
        in.seekg(0, in.beg);       // 复原指针

        // 读取文件
        std::string content;
        content.resize(filesize);
        in.read((char *)content.c_str(), filesize);

        in.close();
        return content;
    }

public:
    HttpServer()
    {
        // 预先加载几个 mime_type
        _mime_type.insert(std::make_pair(".html", "text/html"));
        _mime_type.insert(std::make_pair(".jpg", "image/jpeg"));
        _mime_type.insert(std::make_pair(".png", "image/png"));
        _mime_type.insert(std::make_pair(".default", "text/html"));

        _code_to_desc.insert(std::make_pair(100, "Continue"));
        _code_to_desc.insert(std::make_pair(200, "OK"));
        _code_to_desc.insert(std::make_pair(201, "Created"));
        _code_to_desc.insert(std::make_pair(301, "Moved Permanently"));
        _code_to_desc.insert(std::make_pair(302, "Found"));
        _code_to_desc.insert(std::make_pair(404, "Not Found"));
    }

    void InsertService(const std::string& sername, func_t f)
    {
        std::string s = prefixpath + sername; // 资源路径
        _service_list[s] = f;
    }

    std::string HandlerHttpRequest(std::string &reqstr)
    {
// #define TEST
#ifdef TEST
        // 直接把 http 请求打印出来看看
        std::cout << "--------------" << std::endl;
        std::cout << reqstr; // 不要打印换行

        // 返回一个响应
        std::string respstr = "HTTP/1.1 200 OK\r\n";                 // 状态行
        respstr += "Content-Type: text/html\r\n";                    // 响应报头
        respstr += "\r\n";                                           // 空行
        respstr += "<html><h1>hello linux, hello http!</h1></html>"; // 响应正文

        return respstr;
#else
        // 直接把 http 请求打印出来看看
        std::cout << "--------------" << std::endl;
        std::cout << reqstr;
        std::cout << "--------------" << std::endl;
        HttpRequest req;
        HttpResponse resp;
        req.Deserialize(reqstr);

        std::cout << req.GetRequestBody() << std::endl;
        if (req.Path() == "wwwroot/redir")
        {
            // 处理重定向

            std::string redir_path = "https://news.qq.com/";
            // 添加状态码
            resp.AddCode(302, _code_to_desc[302]);
            // 添加报头
            resp.AddHeader("Location", redir_path);
        }
        else if (!req.GetRequestBody().empty())
        {
            // 参数非空，检查服务是否存在
            if (_service_list.count(req.Path()))
            {
                // 服务存在，执行，返回响应
                resp = _service_list[req.Path()](req);
            }
        }
        else
        {
            // 处理静态资源
            std::string content = GetFileContent(req.Path());
            if (content.empty())
            {
                // 访问的资源不存在
                std::string content = GetFileContent("wwwroot/404.html");
                resp.AddBodyText(content);
                resp.AddCode(404, _code_to_desc[404]);
                resp.AddHeader("Content-Length", std::to_string(content.size()));
                resp.AddHeader("Content-Type", _mime_type[".html"]);
            }
            else
            {
                resp.AddBodyText(content);
                resp.AddCode(200, _code_to_desc[200]);
                resp.AddHeader("Content-Length", std::to_string(content.size()));
                resp.AddHeader("Content-Type", _mime_type[req.Suffix()]);
            }
        }

        // 序列化
        return resp.Serialize();
#endif
    }

private:
    std::unordered_map<std::string, std::string> _mime_type; // 文件后缀与 Content-Type
    std::unordered_map<int, std::string> _code_to_desc;      // 状态码-状态描述
    std::unordered_map<std::string, func_t> _service_list; // 服务列表
};